package com.healthcarex.hip.saas.security.service.impl;

import com.healthcarex.hip.saas.common.model.BaseModel;
import com.healthcarex.hip.saas.common.util.tree.TreeUtils;
import com.healthcarex.hip.saas.security.dao.ResourceDao;
import com.healthcarex.hip.saas.security.model.SysResource;
import com.healthcarex.hip.saas.security.model.SysRoleResource;
import com.healthcarex.hip.saas.security.service.IResourceService;
import com.healthcarex.hip.saas.security.service.IRoleResourceService;
import com.healthcarex.hip.saas.security.util.SecurityUtils;
import com.healthcarex.hip.saas.mybatis.service.impl.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @author chenpan
 * @ClassName: ResourceServiceImpl
 * description:
 * @date 2018-04-02 17:42
 */
@Service
public class ResourceServiceImpl extends BaseServiceImpl<SysResource> implements IResourceService {

    @Autowired
    private ResourceDao resourceDao;

    @Autowired
    private IRoleResourceService roleResourceService;


    @Override
    @CacheEvict(value = {"authority", "resource:tree", "permission"}, allEntries = true)
    public int save(SysResource entity) {
        return super.save(entity);
    }

    @Override
    @CacheEvict(value = {"authority", "resource:tree", "permission"}, allEntries = true)
    public int delete(Object id) {
        return super.delete(id);
    }

    @Override
    @CacheEvict(value = {"authority", "resource:tree", "permission"}, allEntries = true)
    public int updateAll(SysResource entity) {
        return super.updateAll(entity);
    }

    @Override
    @CacheEvict(value = {"authority", "resource:tree", "permission"}, allEntries = true)
    public int updateNotNull(SysResource entity) {
        return super.updateNotNull(entity);
    }

    @Override
    public List<SysResource> findUserPermissions(String username) {
        return this.resourceDao.findUserPermissions(username);
    }

    @Override
    @Cacheable(value = "permission", key = "'user_'.concat(#p0)")
    public Set<String> getStringPermissions(String username) {
        List<SysResource> permissionList = resourceDao.findUserPermissions(username);
        Set<String> permissionSet = new HashSet<>();
        if (permissionList != null) {
            for (SysResource r : permissionList) {
                if (StringUtils.isNotBlank(r.getPermission())) {
                    permissionSet.add(r.getPermission());
                }
            }
        }
        return permissionSet;
    }

    @Override
    @Cacheable(value = "authority", key = "'user_'.concat(#p0)")
    public Set<String> getAuthorities(String username) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Set<String> authorities = new HashSet<>();
        authentication.getAuthorities().stream().forEach(a -> authorities.add(((GrantedAuthority) a).getAuthority()));

        return authorities;
    }

    @Override
    @Cacheable(value = "resource:tree", key = "'user_'.concat(#p0)")
    public List<SysResource> findUserSysResources(String username, List<Integer> appIds) {
        return TreeUtils.buildTree(this.resourceDao.findUserMenus(username, appIds));
    }

    @Override
    public List<SysResource> findAllSysResources(SysResource resource) {
        Example example = new Example(SysResource.class);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(resource.getResourceName())) {
            criteria.andCondition("resource_name=", resource.getResourceName());
        }
        if (StringUtils.isNotBlank(resource.getResourceType())) {
            criteria.andCondition("resource_type=", resource.getResourceType());
        }
        example.setOrderByClause("id");
        return this.selectByExample(example);
    }

    @Override
    @Cacheable(value = "resource:tree", key = "#p0.getAppIdsStr()+'_'+#p0.resourceName+'_'+#p0.requestType")
    public List<SysResource> findResourcesTree(SysResource resource) {
        return TreeUtils.buildTree(resourceDao.findResources(resource));
    }

    @Override
    public List<SysResource> findResources(SysResource resource) {
        return resourceDao.findResources(resource);
    }

    @Override
    public List<SysResource> getMenuButtonTree() {
        return null;
    }

    @Override
    public List<SysResource> getMenuTree() {
        return null;
    }

    @Override
    public List<SysResource> getUserMenu(String username) {
        return null;
    }

    @Override
    public SysResource findById(Integer id) {
        return this.selectById(id);
    }

    @Override
    public SysResource findByNameAndType(String resourceName, String type) {
        Example example = new Example(SysResource.class);
        example.createCriteria().andCondition("lower(resource_name)=", resourceName.toLowerCase()).
                andEqualTo("resource_type",
                        type);
        List<SysResource> list = this.resourceDao.selectByExample(example);
        if (list.size() == 0) {
            return null;
        } else {
            return list.get(0);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    @CacheEvict(value = {"resource:tree", "permission"}, allEntries = true)
    public void addSysResource(SysResource resource) {
        resource.setId(this.getSequence(BaseModel.BASE_SEQ));
        resource.setCreateBy(SecurityUtils.getUsername());
        resource.setCreateTime(new Date());
        if (resource.getParentId() == null) {
            resource.setParentId(0);
        }
        this.save(resource);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void updateSysResource(SysResource resource) {
        resource.setUpdateBy(SecurityUtils.getUsername());
        resource.setUpdateTime(new Date());
        if (resource.getParentId() == null) {
            resource.setParentId(0);
        }
        this.updateNotNull(resource);

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    @CacheEvict(value = {"resource:tree", "permission"}, allEntries = true)
    public void deleteResources(String resourceIds) {
        List<String> list = Arrays.asList(resourceIds.split(","));
        this.batchDelete(list, "id", SysResource.class);
        this.roleResourceService.deleteRoleResourceByResourceId(resourceIds);
        /*this.resourceDao.changeToTop(list);*/
    }
}
